using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions;
using Framework;
using System.Linq;

namespace FrameworkEditor
{
    public class SceneAbSettingTool
    {
        private static string dynamiceTexDir = "Assets/ZResourcesLib/scenes/dynamic/textures/";
        private static string dynamiceDir = "Assets/ZResourcesLib/scenes/dynamic/";
        private static string sceneDir = "Assets/ZResourcesLib/scenes/";
        private static string effectTexDir = "Assets/ZResourcesLib/effects/";
        private static string uieffectTexDir = "Assets/ZResourcesLib/ui/textures/";
        private static string rolesBufferDir = "Assets/ZResourcesLib/rolesbuff/";


        private static Regex includeRegex = new Regex("(.png|.jpg|.tga|.png.meta|.tga.meta|.jpg.meta)$");
        private static Regex ignoreRegex = new Regex("(.meta|.git)$");
        private static Regex texRegex = new Regex("(.png|.jpg|.tga|.exr)$");
        private static Regex roomMatExcludeRegex = new Regex("(bxhy_ground_|bxhy_terrain_)");
        private static string roomMatPath = "scenes/m_s07_xiaowu/mats";
        private static string roomMatVerPath = "scenes/m_s07_xiaowu/mats/room";
        private static string roomBlockDir = "Assets/ZResourcesLib/room/block";
        private static string roomBlockExcludePath = "scenes/m_s07_xiaowu/prefab/block";
        private static string roomVatPath = "scenes/m_s07_xiaowu/vat";
        //荒原不需要单独打预制体的目录
        private static List<string> excludePathList = new List<string>{
            "scenes/m_s07_xiaowu/prefab/block",
            "scenes/m_s07_xiaowu/prefab/heliu",
            "scenes/m_s07_xiaowu/prefab/heliu_floor",
            "room/block",
        };
        //TODO 2.0先把empty.png打到各自ab里，2.2再加增量抽公共逻辑
        private static HashSet<string> FilterCommon = new HashSet<string>
        {
            "Assets/ZResourcesLib/scenes/common/textures/empty.png"
        };
        // [MenuItem("Test/SceneMoveTexture")]
        public static void MoveTexture()
        {
            foreach (string file in Directory.GetFiles(dynamiceTexDir, "*.*", SearchOption.AllDirectories))
            {
                string filePath = FileHelper.GetUnityPath(file);

                if (includeRegex.IsMatch(filePath))
                {
                    string srcPath = filePath.Replace(dynamiceDir, "");
                    string[] splites = srcPath.Split('/');
                    if (splites.Length > 2)
                    {
                        srcPath = Path.Combine(splites[1], splites[0]);
                        for (int idx = 2; idx < splites.Length; idx++)
                        {
                            srcPath = Path.Combine(srcPath, splites[idx]);
                        }
                        srcPath = sceneDir + FileHelper.GetUnityPath(srcPath);
                        Debug.Log($"filePath = {filePath} srcDir = {srcPath}");
                        FileHelper.EnsureDirForFile(srcPath);
                        FileHelper.MoveFile(filePath, srcPath);
                    }
                }
            }
            AssetDatabase.Refresh();
        }

        [MenuItem("Test/SceneAbSettings")]
        public static void PrintSceneAbSettings()
        {
            GetAbSettings();
        }

        public static void BuildCommonEffectTexCfg()
        {

        }

        public static List<AssetBundleBuild> GetAbSettings()
        {
            List<AssetBundleBuild> ret = new List<AssetBundleBuild>();
            Dictionary<string, int> texRefTab = new Dictionary<string, int>();
            Dictionary<string, int> roomMatRefTab = new Dictionary<string, int>();
            Dictionary<string, HashSet<string>> tex2RoomBigABTab = new Dictionary<string, HashSet<string>>();
            string log = "perfab ab:\n";
            var sceneArr = Directory.GetFiles(sceneDir, "*.prefab", SearchOption.AllDirectories);
            var roomBlockArr = Directory.GetFiles(roomBlockDir, "*.prefab", SearchOption.AllDirectories);
            var allArr = sceneArr.Concat(roomBlockArr);
            foreach (string file in allArr)
            {
                string filePath = FileHelper.GetUnityPath(file);
                if (filePath.Contains(roomBlockExcludePath))
                {
                    continue;
                }
                bool isRoomBigAB = false;
                foreach (var v in excludePathList)
                {
                    if (filePath.Contains(v))
                    {
                        isRoomBigAB = true;
                        continue;
                    }
                }
                string[] deps = AssetDatabase.GetDependencies(filePath);
                string depsLog = "";
                foreach (var dependencyItem in deps)
                {
                    string dep = FileHelper.GetUnityPath(dependencyItem);
                    if (dep.Contains(roomVatPath)) continue;
                    if (texRegex.IsMatch(dep))
                    {
                        depsLog += (dep + "\n");
                        if (!dep.StartsWith(sceneDir))
                        {
                            if (!dep.StartsWith(effectTexDir) && !dep.StartsWith(uieffectTexDir) && !dep.StartsWith(rolesBufferDir))
                            {
                                Debug.LogWarning($"scene prefab:{filePath} can not ref dep:{dep}");
                            }
                            continue;
                        }
                        if (isRoomBigAB)
                        {
                            if (tex2RoomBigABTab.ContainsKey(dep) == false)
                            {
                                tex2RoomBigABTab[dep] = new HashSet<string>();
                            }

                            var bigAbName = EditorUtils.GetRelativePathToDir(Path.GetDirectoryName(filePath), EditorUtils.assetRootDir);
                            if (tex2RoomBigABTab[dep].Contains(bigAbName) == false)
                            {
                                tex2RoomBigABTab[dep].Add(bigAbName);
                            }
                            if (texRefTab.ContainsKey(dep) == false)
                            {
                                texRefTab[dep] = 0;
                            }
                        }
                        else
                        {
                            if (texRefTab.ContainsKey(dep))
                            {
                                texRefTab[dep]++;
                            }
                            else
                            {
                                texRefTab[dep] = 1;
                            }
                        }
                    }
                    else if (dep.Contains(roomMatVerPath))
                    {
                        if (roomMatExcludeRegex.IsMatch(dep) == false)
                        {
                            if (roomMatRefTab.ContainsKey(dep))
                            {
                                roomMatRefTab[dep]++;
                            }
                            else
                            {
                                roomMatRefTab[dep] = 1;
                            }
                        }
                    }
                }
                // Debug.Log($"filePath = {filePath} deps = {depsLog}");
                if (isRoomBigAB) continue;

                string assetPath = EditorUtils.GetPathRelativeToAssets(file);
                string abName = EditorUtils.GetRelativePathToDir(assetPath, EditorUtils.assetRootDir) + FrameworkSettings.AssetBundleExt;
                log += ($"abName:{abName} assetPath:{assetPath}\n");
                ret.Add(new AssetBundleBuild()
                {
                    assetBundleName = abName,
                    assetNames = new string[] { assetPath },
                });
            }

            int count = 0;
            log += "\n room mat ab:\n";
            List<string> tmp = new List<string>();

            foreach (var item in roomMatRefTab)
            {
                string assetPath = EditorUtils.GetPathRelativeToAssets(item.Key);
                int prefabRefCount = item.Value;
                if (prefabRefCount > 1)
                {
                    tmp.Add(item.Key);
                    string abName = EditorUtils.GetRelativePathToDir(assetPath, EditorUtils.assetRootDir) + FrameworkSettings.AssetBundleExt;
                    // log += ($"abName:{abName} assetPath:{assetPath}  prefabRefCount:{prefabRefCount}\n");
                    ret.Add(new AssetBundleBuild()
                    {
                        assetBundleName = abName,
                        assetNames = new string[] { assetPath },
                    });
                    count++;
                }
            }
            log += ($"room dynamic mat ab count = {count} \n");
            tmp.Sort((a, b) =>
{
    int countA = roomMatRefTab[a];
    int countB = roomMatRefTab[b];
    return countA.CompareTo(countB);
});
            for (int i = 0; i < tmp.Count; i++)
            {
                var key = tmp[i];
                log += ($"assetPath:{key} prefabRefCount:{roomMatRefTab[key]}\n");
            }


            Dictionary<string, HashSet<string>> tex2RoomMatABTab = new Dictionary<string, HashSet<string>>();
            var roomMatArr = Directory.GetFiles(FrameworkSettings.AssetRootDir + "/" + roomMatPath, "*.mat", SearchOption.AllDirectories);
            foreach (string file in roomMatArr)
            {
                string filePath = FileHelper.GetUnityPath(file);
                string[] deps = AssetDatabase.GetDependencies(filePath);
                var matAbName = EditorUtils.GetRelativePathToDir(filePath, EditorUtils.assetRootDir);
                foreach (var dependencyItem in deps)
                {
                    string dep = FileHelper.GetUnityPath(dependencyItem);
                    if (texRegex.IsMatch(dep))
                    {
                        if (dep.Contains("scenes/m_s07_xiaowu/textures/"))
                        {
                            if (tex2RoomMatABTab.ContainsKey(dep) == false)
                            {
                                tex2RoomMatABTab[dep] = new HashSet<string>();
                            }
                            string abName;
                            if (roomMatExcludeRegex.IsMatch(filePath) && filePath.Contains("scenes/m_s07_xiaowu/mats/room/"))
                            {
                                abName = EditorUtils.GetRelativePathToDir(Path.GetDirectoryName(filePath), EditorUtils.assetRootDir);
                                if (tex2RoomMatABTab[dep].Contains(abName) == false)
                                {
                                    tex2RoomMatABTab[dep].Add(abName);
                                }
                            }
                            else
                            {
                                if (tmp.Contains(filePath))
                                {
                                    abName = EditorUtils.GetRelativePathToDir(filePath, EditorUtils.assetRootDir);
                                    tex2RoomMatABTab[dep].Add(abName);
                                }
                                else
                                {
                                    tex2RoomMatABTab[dep].Add("1");
                                    tex2RoomMatABTab[dep].Add("2");
                                }
                            }
                        }
                    }
                }
            }

            log += "texture ab:\n";
            count = 0;
            foreach (var item in texRefTab)
            {
                string assetPath = EditorUtils.GetPathRelativeToAssets(item.Key);
                if (!assetPath.StartsWith(sceneDir))
                {
                    continue;
                }
                if (FilterCommon.Contains(assetPath))
                {
                    continue;
                }
                Texture tex = AssetDatabase.LoadAssetAtPath<Texture>(assetPath);
                int prefabRefCount = item.Value;
                int size = tex.width * tex.height;
                if (tex2RoomBigABTab.ContainsKey(item.Key))
                {
                    prefabRefCount += tex2RoomBigABTab[item.Key].Count;
                }
                if (tex2RoomMatABTab.ContainsKey(item.Key))
                {
                    if (tex2RoomMatABTab[item.Key].Count == 1)
                    {
                        // Debug.Log(item.Key + "#" + tex2RoomMatABTab[item.Key].Count);
                        continue;
                    }
                }

                if (prefabRefCount > 1 && size * prefabRefCount >= 256 * 256 * 2)
                {
                    string abName = EditorUtils.GetRelativePathToDir(assetPath, EditorUtils.assetRootDir) + FrameworkSettings.AssetBundleExt;
                    log += ($"abName:{abName} assetPath:{assetPath}\n");
                    ret.Add(new AssetBundleBuild()
                    {
                        assetBundleName = abName,
                        assetNames = new string[] { assetPath },
                    });
                    count++;
                }
            }
            log += ($"scenes dynamic texture ab count = {count}\n");

            FileHelper.WriteTextToPath(Application.dataPath.Replace("Assets", "scenesAbSettings.txt"), log);
            Debug.Log("GetAbSettings finish!");
            System.GC.Collect();
            UnityEngine.Resources.UnloadUnusedAssets();
            System.GC.Collect();
            return ret;
        }
    }
}
